#include <stdio.h>
#include <stdlib.h>
#include "sitetype.h"
#include "mlib.h"
#include <unistd.h>
#include <glob.h>
#include "mytbf.h"
#include <sys/types.h>
#include "proto.h"
#include "server.h"
#include <syslog.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include"mytbf.h"
#include"server.h"

#define LISTMAXSIZE 1024
#define PATHSIZE 1024
#define LINEBUFSIZE 1024
#define MP3_BITRATE 320 * 1024 // 采样率

/* 列表媒体文件属性*/
struct channel_context_st
{
  chnid_t chnid;
  char *desc;
  glob_t mp3glob;
  int pos;
  int fd;
  off_t offset;
  mytbf_t *tbf;
};

struct channel_context_st channel[CHNNR + 1];
  int totalsize;

struct channel_context_st *path2entry(char *gl_pathv)
{
  printf("current path: %s\n", gl_pathv);
  syslog(LOG_INFO, "current path: %s\n", gl_pathv);
  char pathstr[PATHSIZE] = {'\0'};
  char linebuf[LINEBUFSIZE];

  FILE *fp;
  struct channel_context_st *me;
  static chnid_t cur_id = MINCHNID; // 由于是一个静态变量所以相当于一直在操作同一块内存 有叠加效果
  strcat(pathstr, gl_pathv);        // 把gl_pathv里的字符串放到pathstr后面 拼接两个字符串
  strcat(pathstr, "/desc.txt");
  fp = fopen(pathstr, "r"); // 打开频道描述文件
  syslog(LOG_INFO, "channel dir:%s\n", pathstr);
  if (fp == NULL)
  {
    syslog(LOG_INFO, "%s is not a channe; dir (can not find desc.txt)", gl_pathv);
    return NULL;
  }
  if (fgets(linebuf, LINEBUFSIZE, fp) == NULL)
  {
    syslog(LOG_INFO, "%s is not a channel dir(cant get the desc.text)", gl_pathv);
    fclose(fp);
    return NULL;
  }
  fclose(fp); // 关闭频道描述文件
  me = malloc(sizeof(*me));
  if (me == NULL)
  {
    syslog(LOG_ERR, "malloc()%s", strerror(errno));
    return NULL;
  }
  me->tbf = mytbf_init(MP3_BITRATE / 8, MP3_BITRATE / 8 * 5);
  if (me->tbf == NULL)
  {
    syslog(LOG_ERR, "mytbf_init()%s\n", strerror(errno));
    return NULL;
  }
// 拷贝
  me->desc = strdup(linebuf);
  /* warning: 'strncpy' specified bound 1024 equals destination size [-Wstringop-truncation] */
  // 由于上面的警告, 所以要对第三个参数-1
  strncpy(pathstr, gl_pathv, PATHSIZE - 1);
  strncat(pathstr, "/*.mp3", PATHSIZE - 1);
  if (glob(pathstr, 0, NULL, &me->mp3glob) != 0)
  {
    // cur_id++;
    syslog(LOG_ERR, "%s is not a channel dir(can not find mp3 files", gl_pathv);
    free(me);
    return NULL;
  }
  me->pos = 0;
  me->offset = 0;
  me->fd = open(me->mp3glob.gl_pathv[me->pos], O_RDONLY);
  if (me->fd < 0)
  {
    syslog(LOG_WARNING, "%s open failed.", me->mp3glob.gl_pathv[me->pos]);
    free(me);
    return NULL;
  }

  me->chnid = cur_id;
  cur_id++;
  return me;
}

int mlib_freechnlist(struct msg_listentry_st *ptr) 
{
  free(ptr);
  return 0;
}

/* 根据目录解析频道 */
int mlib_getchnlist(struct msg_list_st **mchnarr, int *index)
{
  char path[PATHSIZE];
  glob_t globres;
  int size = 0;
  int i;
  int num = 0;
/****************换msg_listentry_st************************************/
  struct msg_listentry_st *ptr = NULL;
  struct msg_list_st *entrylistptr;  //节目单总包
  struct channel_context_st *res;

  for (i = 0; i < CHNNR + 1; i++)
  {
    channel[i].chnid = -1;
  }
  // int snprintf(char *str, size_t size, const char *format, ...) 按照format的格式格式化为字符串，然后再将其拷贝至str中
  snprintf(path, PATHSIZE, "%s/*", server_conf.media_dir);

  if (glob(path, 0, NULL, &globres) < 0) //根据path解析目录，返回一个列表
  {
    return -1;
  }

   totalsize = sizeof(chnid_t);

   /********************************************************************malloc********/
   entrylistptr = malloc(MSG_LIST_MAX/CHNNR*globres.gl_pathc);
    if(entrylistptr == NULL)
   {
       syslog(LOG_ERR, "malloc() failed.%s", strerror(errno));
       exit(1);
   }
   entrylistptr->chnid = LISTCHNID;
 
      
ptr = entrylistptr->entry;

  for (i = 0; i < globres.gl_pathc; i++) 
  {
    // globres.gl_pathv[i]  -> "/var/media/ch1"
    //根据列表文件的内容返回
    res = path2entry(globres.gl_pathv[i]);
    if (res != NULL)
    {
      syslog(LOG_DEBUG, "path2entry () :%d  %s\n", res->chnid, res->desc);

         totalsize += sizeof(struct msg_listentry_st)+strlen(res->desc);
        //  ptr = realloc(ptr, totalsize);

        /*            （1）sizeof是用来求某种类型的变量所占用的内存大小的。
                               

             （2）strlen顾名思义，是用来求string的length的。
      */
    size = sizeof(struct msg_listentry_st)+strlen(res->desc); //如果用sizeof(res->decs)会丢失数据
#ifdef DEBUG
    printf("strlen = %d\n", strlen(res->desc));
    printf("sizeof = %d\n", sizeof(char *));
#endif // DEBUG

     ptr->chnid = res->chnid;
     ptr->len = htons(size);
    strcpy((char *) ptr->desc, res->desc);
     ptr = (void *)(((char *) ptr) + size); // 向后移动ptr
/*       把可以用的频道结构体保存                 */
      memcpy(channel + res->chnid, res, sizeof(*res)); //加res->chnid  代表第几个频道  与&channel[res->chnid]效果相同

      #ifdef DEBUG
           printf("sizeof(*res)%d\n", sizeof(*res));
      #endif // DEBUG
 
      num++;
      
    }
  }


// *mchnarr = ptr;

  *mchnarr = realloc(entrylistptr, totalsize); //重新分配内存大小
  if (*mchnarr == NULL)
  {
    syslog(LOG_ERR, "realloc() failed.");
  }
  *index = num;

#ifdef DEBUG
  printf("1111111totalsize = %d\n", totalsize);
#endif // DEBUG

  return 0;
}

/**********************************************************************/
static int open_next(chnid_t chnid)
{
  for (int i = 0; i < channel[chnid].mp3glob.gl_pathc; ++i)
  {
    channel[chnid].pos++; // 更新偏移
    if (channel[chnid].pos == channel[chnid].mp3glob.gl_pathc)
    {
      syslog(LOG_INFO, "没有文件了\n");
      channel[chnid].pos = 0;
    }
    close(channel[chnid].fd);

    // 尝试打开新文件
    channel[chnid].fd =
        open(channel[chnid].mp3glob.gl_pathv[channel[chnid].pos], O_RDONLY);
    if (channel[chnid].fd < 0)
    {
      syslog(LOG_WARNING, "open(%s):%s", channel[chnid].mp3glob.gl_pathv[chnid],
             strerror(errno));
    }
    else
    {
      printf("打开新文件了\n");
      channel[chnid].offset = 0;
      return 0;
    }
  }
  syslog(LOG_ERR, "None of mp3 in channel %d id available.", chnid);
  return -1;
}

ssize_t mlib_readchn(chnid_t chnid, void *buf, size_t size)
{
  int tbfsize;
  int len;

  // get token number
  tbfsize = mytbf_fetchtoken(channel[chnid].tbf, size);
  syslog(LOG_INFO, "current tbf():%d\n", mytbf_checktoken(channel[chnid].tbf));

  while (1)
  {
    /*  从fd中读取tbfsize大小的数据到buf中，读取地址=文件开始+offset*/
    len = pread(channel[chnid].fd, buf, tbfsize, channel[chnid].offset); // 读取tbfsize数据到从offset处开始的buf
    /*current song open failed*/
    if (len < 0)
    {
      // 当前这首歌可能有问题，错误不至于退出，读取下一首歌
      syslog(LOG_WARNING, "media file %s pread():%s",
             channel[chnid].mp3glob.gl_pathv[channel[chnid].pos],
             strerror(errno));
      if(open_next(chnid) <0)
      {
         syslog(LOG_ERR, "channel %d no successed open",channel[chnid].chnid);
      }
    }
    else if (len == 0)
    {
      syslog(LOG_DEBUG, "media %s file is over",
             channel[chnid].mp3glob.gl_pathv[channel[chnid].pos]);
#ifdef DEBUG
      printf("current chnid :%d\n", chnid);
#endif
      open_next(chnid);
      break;
    }
    else /*len > 0*/ //真正读取到了数据
    {
      channel[chnid].offset += len;
      // struct stat buf;
      // fstat(channel[chnid].fd, &buf);
      // syslog(LOG_DEBUG, "epoch : %f%%",
      //        (channel[chnid].offset) / (1.0 * buf.st_size) * 100);
      break;
    }
  }
  // remain some token
  if (tbfsize - len > 0)
    mytbf_returntoken(channel[chnid].tbf, tbfsize - len);
  printf("current chnid :%d\n", chnid);
  return len; //返回读取到的长度
}

